package MyThread_demo.shendu_study_ReentrantLock;

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

/**
 * @author ChenYongHao
 * @date 2023/5/4 14:27
 * @desc
 * 多条件
 *
 * synchronized 中也有条件变量，就是 waitSet 休息室，当条件不满足时进入 waitSet 等待,
 * ReentrantLock 的条件变量比 synchronized 强大之处在于，它是支持多个条件变量的,
 * 这就好比 synchronized 是那些不满足条件的线程都在一间休息室等消息,
 * 而 ReentrantLock 支持多间休息室，有专门等烟的休息室、专门等早餐的休息室、唤醒时也是按休息室来唤醒。
 *
 * 使用要点：
 *
 * await 前需要获得锁
 * await 执行后，会释放锁，进入 conditionObject 等待
 * await 的线程被唤醒（或打断、或超时）去重新竞争 lock 锁
 * 竞争 lock 锁成功后，从 await 后继续执行
 */
public class await多条件 {
    public static ReentrantLock lock = new ReentrantLock();
    public static Condition waitCigaretteQueue = lock.newCondition();
    public static Condition waitbreakfastQueue = lock.newCondition();
    public static volatile boolean hasCigrette = false;
    public static volatile boolean hasBreakfast = false;

    public static void main(String[] args) throws InterruptedException {
        new Thread(() -> {
            try {
                lock.lock();
                while (!hasCigrette) {
                    try {
                        waitCigaretteQueue.await();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                System.out.println("小明等到了它的烟");
            } finally {
                lock.unlock();
            }
        },"小明").start();
        new Thread(() -> {
            try {
                lock.lock();
                while (!hasBreakfast) {
                    try {
                        waitbreakfastQueue.await();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                System.out.println("小红等到了它的早餐");
            } finally {
                lock.unlock();
            }
        },"小红").start();
        Thread.sleep(1000);
        sendBreakfast();
        Thread.sleep(1000);
        sendCigarette();
    }

    private static void sendCigarette() {
        lock.lock();
        try {
            System.out.println("送烟来了");
            hasCigrette = true;
            waitCigaretteQueue.signal();
        } finally {
            lock.unlock();
        }
    }

    private static void sendBreakfast() {
        lock.lock();
        try {
            System.out.println("送早餐来了");
            hasBreakfast = true;
            waitbreakfastQueue.signal();
        } finally {
            lock.unlock();
        }
    }
}
